
import logging

from google.appengine.ext import db

SESSIONS = [
  '2012-01', '2012-04',
  '2012-09-02', '2012-09-28',
  '2012-10-29', '2012-11-30',
  '2013-02-28', '2013-04-24'
]

CURRENT_SESSION = '2013-04-24'


def model_to_dict(model):
  model_dict = {}
  for p in model.properties():
    if getattr(model, p) is not None:
      if isinstance(getattr(model, p), db.Model):
        model_dict[p] = getattr(model, p).to_dict()
      else:
        model_dict[p] = getattr(model, p)
  if model.is_saved():
    model_dict['id'] = model.key().id()
  return model_dict


def dict_to_model(model_dict, model):
  for key, value in model_dict.iteritems():
    if hasattr(model, key):
      if not isinstance(value, dict):
        setattr(model, key, value)


def clone_entity(e, **extra_args):
  klass = e.__class__
  props = dict((k, v.__get__(e, klass)) for k, v in klass.properties().iteritems())
  props.update(extra_args)
  return klass(**props)


def updateModelsInBatches(model_class, update_func, session=CURRENT_SESSION,
    offset=0, limit=200):
  query = model_class.all()
  query.ancestor(model_class.gen_key())
  query.filter('session = ', session)
  while True:
    db_models = query.fetch(limit=limit, offset=offset)
    if len(db_models) > 0:
      updated_models = []
      for db_model in db_models:
        updated_models.append(update_func(db_model))
      db.put(updated_models)
      offset += limit
    else:
      return


class StudentSession(db.Model):
  session = db.StringProperty()
  student_id = db.IntegerProperty()
  dorm = db.StringProperty()
  room = db.StringProperty()
  ra = db.StringProperty()
  consented = db.BooleanProperty()
  # Status stores the id of the user's current survey section.
  status = db.StringProperty()
  previous_session_status = db.StringProperty()

  @staticmethod
  def gen_key(id=None):
    if id is None:
      return db.Key.from_path('StudentSession', 'default')
    else:
      return db.Key.from_path('StudentSession', 'default', 'StudentSession', id)

  def to_dict(self):
    return model_to_dict(self)

  def merge_from_dict(self, student_session_dict):
    dict_to_model(student_session_dict, self)


class Student(db.Model):
  email_address = db.StringProperty()
  first_name = db.StringProperty()
  middle_name = db.StringProperty()
  last_name = db.StringProperty()
  gaia_user = db.UserProperty()
  admin = db.BooleanProperty()
  current_session = db.StringProperty()
  current_session_data = db.ReferenceProperty(StudentSession)
  #REMOVE
  deleted = db.BooleanProperty()
  dorm = db.StringProperty()
  room = db.StringProperty()
  ra = db.StringProperty()
  consented = db.BooleanProperty()
  session = db.StringProperty()
  status = db.StringProperty()
  previous_session_status = db.StringProperty()

  @staticmethod
  def gen_key(id=None):
    if id is None:
      return db.Key.from_path('Student', 'default')
    else:
      return db.Key.from_path('Student', 'default', 'Student', id)

  def to_dict(self):
    student_dict = model_to_dict(self)
    if student_dict.has_key('fb_profile'):
      del student_dict['fb_profile']
    if student_dict.has_key('fb_friends'):
      del student_dict['fb_friends']
    if student_dict.has_key('fb_matches'):
      del student_dict['fb_matches']
    return student_dict

  def merge_from_dict(self, student_dict):
    dict_to_model(student_dict, self)

  def clone(self):
    return clone_entity(self, parent=Student.gen_key())


class FacebookData(db.Model):
  session = db.StringProperty()
  student_id = db.IntegerProperty()
  fb_id = db.StringProperty()
  fb_profile = db.TextProperty()
  fb_friends = db.TextProperty()
  fb_matches = db.TextProperty()
  # Legacy student ID.
  LSID = db.IntegerProperty()

  @staticmethod
  def gen_key(id=None):
    if id is None:
      return db.Key.from_path('FacebookData', 'default')
    else:
      return db.Key.from_path('FacebookData', 'default', 'FacebookData', id)


class Answer(db.Model):
  session = db.StringProperty()
  student_id = db.IntegerProperty()
  section_id = db.StringProperty()
  question_id = db.StringProperty()
  values = db.StringListProperty()
  other_value = db.StringProperty()
  # Legacy student ID.
  LSID = db.IntegerProperty()

  @staticmethod
  def gen_key(id=None):
    if id is None:
      return db.Key.from_path('Answer', 'default')
    else:
      return db.Key.from_path('Answer', 'default', 'Answer', id)

  def to_dict(self):
    return model_to_dict(self)

  def merge_from_dict(self, answer_dict):
    dict_to_model(answer_dict, self)
  

class FriendSurvey(db.Model):
  session = db.StringProperty()
  student_id = db.IntegerProperty()
  friend = db.ReferenceProperty(Student)
  relation_type = db.IntegerProperty()
  friendship_level = db.IntegerProperty()
  interaction_level = db.IntegerProperty()
  ask_advice_level = db.IntegerProperty()
  trust_level = db.IntegerProperty()
  is_random_friend = db.BooleanProperty()
  first_met_location = db.StringProperty()
  first_met_interation = db.StringProperty()
  # Legacy student ID.
  LSID = db.IntegerProperty()
  F_LSID = db.IntegerProperty()

  @staticmethod
  def gen_key(id=None):
    if id is None:
      return db.Key.from_path('FriendSurvey', 'default')
    else:
      return db.Key.from_path('FriendSurvey', 'default', 'FriendSurvey', id)

  def to_dict(self):
    return model_to_dict(self)

  def merge_from_dict(self, friend_survey_dict):
    dict_to_model(friend_survey_dict, self)

  def clone(self):
    cloned_entity = clone_entity(self, parent=FriendSurvey.gen_key())
    return cloned_entity


class StrainedFriendSurvey(db.Model):
  session = db.StringProperty()
  student_id = db.IntegerProperty()
  friend = db.ReferenceProperty(Student)
  relationship_level = db.IntegerProperty()
  # Legacy student ID.
  LSID = db.IntegerProperty()
  F_LSID = db.IntegerProperty()

  @staticmethod
  def gen_key(id=None):
    if id is None:
      return db.Key.from_path('StrainedFriendSurvey', 'default')
    else:
      return db.Key.from_path('StrainedFriendSurvey', 'default',
          'StrainedFriendSurvey', id)

  def to_dict(self):
    return model_to_dict(self)

  def merge_from_dict(self, strained_friend_survey_dict):
    dict_to_model(strained_friend_survey_dict, self)
